/**
 * 设计一个简化版的推特(Twitter)，可以让用户实现发送推文，关注/取消关注其他用户，能够看见关注人（包括自己）的最近 10 条推文。
 *
 * 实现 Twitter 类：
 *
 * Twitter() 初始化简易版推特对象
 * void postTweet(int userId, int tweetId) 根据给定的 tweetId 和 userId 创建一条新推文。每次调用此函数都会使用一个不同的 tweetId 。
 * List<Integer> getNewsFeed(int userId) 检索当前用户新闻推送中最近 10 条推文的 ID 。新闻推送中的每一项都必须是由用户关注的人或者是用户自己发布的推文。推文必须 按照时间顺序由最近到最远排序 。
 * void follow(int followerId, int followeeId) ID 为 followerId 的用户开始关注 ID 为 followeeId 的用户。
 * void unfollow(int followerId, int followeeId) ID 为 followerId 的用户不再关注 ID 为 followeeId 的用户。
 *
 *
 * 链接：https://leetcode.cn/problems/design-twitter
 */
class Twitter {
    private static int timestamp=0;
    private static class Tweet{
        private int id;
        private int time;
        private Tweet next;
        public Tweet(int id,int time) {
            this.id=id;
            this.time=time;
            this.next=null;
        }
    }
    private static class User{
        private int id;
        public Set<Integer> followed;
        public Tweet head;
        public User(int userId) {
            this.id=userId;
            followed=new HashSet<>();
            this.head=null;
            follow(id);
        }
        public void follow(int userId) {
            followed.add(userId);
        }
        public void unfollow(int userId) {
            if(this.id!=userId) {
                followed.remove(userId);
            }
        }
        public void post(int tweetId) {
            Tweet twt=new Tweet(tweetId,timestamp);
            timestamp++;
            twt.next=head;
            head=twt;
        }
    }
    private Map<Integer,User> userMap=new HashMap<>();
    public Twitter() {

    }
    
    public void postTweet(int userId, int tweetId) {
        if(!userMap.containsKey(userId)) {
            userMap.put(userId,new User(userId));
        }
        User u=userMap.get(userId);
        u.post(tweetId);

    }
    
    public List<Integer> getNewsFeed(int userId) {
        List<Integer> ret=new ArrayList<>();
        if(!userMap.containsKey(userId))
        return ret;
        Set<Integer> users=userMap.get(userId).followed;
        PriorityQueue<Tweet> qu=new PriorityQueue<>(users.size(),(a,b)->(b.time-a.time));
        for(int id:users) {
            Tweet twt=userMap.get(id).head;
            if(twt==null)
            continue;
            qu.add(twt);
        }
        while(!qu.isEmpty()) {
            if(ret.size()==10)
            break;
            Tweet twt=qu.poll();
            ret.add(twt.id);
            if(twt.next!=null) {
                qu.add(twt.next);
            }
        }
        return ret;
    }
    
    public void follow(int followerId, int followeeId) {
        if(!userMap.containsKey(followerId)) {
            User u=new User(followerId);
            userMap.put(followerId,u);
        }
        if(!userMap.containsKey(followeeId)) {
            User u=new User(followeeId);
            userMap.put(followeeId,u);
        }
        userMap.get(followerId).follow(followeeId);
    }
    
    public void unfollow(int followerId, int followeeId) {
        if(userMap.containsKey(followerId)) {
            User flwer=userMap.get(followerId);
            flwer.unfollow(followeeId);
        }
    }
}

/**
 * Your Twitter object will be instantiated and called as such:
 * Twitter obj = new Twitter();
 * obj.postTweet(userId,tweetId);
 * List<Integer> param_2 = obj.getNewsFeed(userId);
 * obj.follow(followerId,followeeId);
 * obj.unfollow(followerId,followeeId);
 */